#pragma once
#include "BaseQueue.h"

template <typename T>
class LinkedQueue : public BaseQueue<T>
{
private :
	typedef struct _QueueNode {
		_QueueNode* pPrevNode;
		T data;
		_QueueNode(const T& init = T()) : data(init) { }
	}QueueNode, *LPQueueNode;

	const int m_nMaxSize;
	QueueNode* m_pMinNode;
	QueueNode* m_pMaxNode;
	void clearQueueNodes();
public :
	LinkedQueue(int a_nMaxSize);
	~LinkedQueue();

	virtual void offer(T a_oData);
	virtual T poll();
	virtual T peek();
	virtual bool canOffer();
	virtual bool canPoll();
	virtual int getDataCount();

};

template <typename T>
LinkedQueue<T>::LinkedQueue(int a_nMaxSize) : m_nMaxSize(a_nMaxSize)
{
	m_pMinNode = NULL;
	m_pMaxNode = NULL;
}

template <typename T>
LinkedQueue<T>::~LinkedQueue()
{
	clearQueueNodes();
}

template <typename T>
void LinkedQueue<T>::clearQueueNodes() 
{
	while(m_pMaxNode != NULL) {
		QueueNode* pDeletingNode = m_pMaxNode;
		m_pMaxNode = m_pMaxNode->pPrevNode;
		delete(pDeletingNode);
	}

	m_pMinNode = NULL;
	m_pMaxNode = NULL;
}

template <typename T>
void LinkedQueue<T>::offer(T a_oData) {

	if(canOffer() == false) 
	{
		throw DSFullFilledException();
	}

	QueueNode* pNewNode = new QueueNode;
	pNewNode->data = a_oData;
	pNewNode->pPrevNode = NULL;

	if(m_pMinNode == NULL) {
		m_pMinNode = pNewNode;
		m_pMaxNode = pNewNode;
	}
	else {
		m_pMinNode->pPrevNode = pNewNode;
		m_pMinNode = pNewNode;
	}
}

template <typename T>
T LinkedQueue<T>::poll() {

	if(canPoll() == false) {
		throw DSEmptyException();
	}

	T polledData = m_pMaxNode->data;
	QueueNode* deletingNode = m_pMaxNode;

	m_pMaxNode = m_pMaxNode->pPrevNode;
	if(m_pMaxNode == NULL) {
		m_pMinNode = NULL;
	}

	delete deletingNode;

	return polledData;
}

template <typename T>
T LinkedQueue<T>::peek() {

	if(canPoll() == false) {
		throw DSEmptyException();
	}

	T peekedData = m_pMaxNode->data;

	return peekedData;
}

template <typename T>
bool LinkedQueue<T>::canOffer() {

	int currentCount = getDataCount();
	return currentCount < this->m_nMaxSize;
}

template <typename T>
bool LinkedQueue<T>::canPoll() {

	int currentCount = getDataCount();
	return currentCount > 0;
}

template <typename T>
int LinkedQueue<T>::getDataCount() {

	int count = 0;
	QueueNode* pTempNode = m_pMaxNode;

	while(pTempNode != NULL) {
		count++;
		pTempNode = pTempNode->pPrevNode;
	}

	return count;
}